﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using VulnDBExplorer.Services;
using System.Threading;
using Luna;

namespace VulnDBExplorer.Forms
{
	public partial class ProgressForm : Form
	{
		private static ProgressForm activeInstance;
		private List<TaskProgressMonitor> toplevelMonitors;

		public ProgressForm(IAppContext context)
		{
			InitializeComponent();
			TopMost = true;
			ShowDetailed = false;

			toplevelMonitors = new List<TaskProgressMonitor>();

			btnCancel.Click += cancel;
			btnShowDetail.Click += (o, a) => ShowDetailed = !ShowDetailed;
			Context = context;
			activeInstance = this;
		}

		public static ProgressForm Instance {
			get {
				return activeInstance;
			}
		}

		public IAppContext Context { get; set; }

		protected override void OnClosing(CancelEventArgs e) {
			if (taskPanel.Controls.Count > 0)
				e.Cancel = true;
			base.OnClosing(e);
		}

		protected override void OnClosed(EventArgs e) {
			activeInstance = null;
			base.OnClosed(e);
		}

		TaskProgressMonitor this[int index] {
			get {
				return (TaskProgressMonitor)taskPanel.Controls[index];
			}
		}

		public bool ShowDetailed {
			get {
				return taskPanel.Visible;
			}
			set {
				btnShowDetail.Text = value ? "Hide <<" : "Show >>";
				taskPanel.Visible = value;
				Height = value ? 340 : 152;
			}
		}

		public IProgressMonitor createTaskMonitor() {
			return createTaskMonitor(null);
		}

		public IProgressMonitor createTaskMonitor(IProgressMonitor parentTask) {
			if (InvokeRequired)
				return (IProgressMonitor)Invoke(new Func<IProgressMonitor>(createTaskMonitor), parentTask);
			else {
				TaskProgressMonitor tm = new TaskProgressMonitor();
				tm.BorderStyle = BorderStyle.FixedSingle;
				tm.Dock = DockStyle.Top;
				tm.Updated += updateTitle;
				tm.Stopped += taskStop;
				tm.Started += taskStart;
				tm.ParentTask = parentTask;

				if (parentTask == null)
					toplevelMonitors.Add(tm);
				return tm;
			}
		}

		private void taskStart(object sender, EventArgs args) {
			if (InvokeRequired)
				Invoke(new EventHandler(taskStart), sender, args);
			else {
				TaskProgressMonitor tm = (TaskProgressMonitor)sender;
				tm.Parent = taskPanel;
				taskPanel.Controls.Add(tm);
				tm.BringToFront();

				if (!ShowDetailed && taskPanel.Controls.Count > 1)
				 	ShowDetailed = true;
				if (!this.Visible) {
					IApplication app = Context.getService<IApplication>();
					app.showForm(this, false);
					this.Invalidate();
				}
			}
		}

		private void updateTitle(object sender, EventArgs args) {
			if (InvokeRequired)
				Invoke(new EventHandler(updateTitle), sender, args);
			else {
				if (toplevelMonitors.Count == 1) {
					TaskProgressMonitor tm = toplevelMonitors[0];
					lblTitle.Text = tm.Title;
					lblDescription.Text = tm.Description;
				}
				else {
					lblTitle.Text = "{0} tasks are executing...".format(toplevelMonitors.Count);
					lblDescription.Text = "";
				}
				int total = 0, value = 0;
				bool marquee = toplevelMonitors.Count == 0;
				foreach (TaskProgressMonitor tm in toplevelMonitors)
					if (tm.Total != int.MaxValue) {
						total += tm.Total;
						value += tm.Value;
					}
					else marquee = true;

				progressBar.Maximum = total;
				progressBar.Value = value;

				if (marquee ^ progressBar.Style == ProgressBarStyle.Marquee)
					progressBar.Style = marquee ? ProgressBarStyle.Marquee : ProgressBarStyle.Continuous;

				this.Refresh();
			}
		}

		private void taskStop(object sender, EventArgs args) {
			if (InvokeRequired)
				Invoke(new EventHandler(taskStop), sender, args);
			else {
				TaskProgressMonitor tm = (TaskProgressMonitor)sender;
				tm.Stopped -= taskStop;
				tm.Updated -= updateTitle;
				taskPanel.Controls.Remove(tm);
				toplevelMonitors.Remove(tm);
				if (taskPanel.Controls.Count == 0)
					Close();
			}
		}

		private void cancel(object sender, EventArgs args) {
			for (int i = taskPanel.Controls.Count - 1; i >= 0; i--)
				this[i].cancel();
		}
	}
}
